home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / winsock / ircii2-6.zip / SRC\IRCII-2.6\SOURCE\SCREEN.C < prev    next >
C/C++ Source or Header  |  1995-01-09  |  47KB  |  2,052 lines

  1. /*
  2.  * screen.c
  3.  *
  4.  * Written By Matthew Green, based on portions of window.c
  5.  * by Michael Sandrof.
  6.  *
  7.  * Copyright(c) 1993, 1994.
  8.  *
  9.  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
  10.  */
  11.  
  12. #ifndef lint
  13. static    char    rcsid[] = "@(#)$Id: screen.c,v 1.24 1994/10/14 23:13:43 mrg Stab $";
  14. #endif
  15.  
  16. #include "irc.h"
  17.  
  18. #ifdef HAVE_SYS_UN_H
  19. # include <sys/un.h>
  20. #endif /* HAVE_SYS_UN_H */
  21.  
  22. #include "screen.h"
  23. #include "menu.h"
  24. #include "window.h"
  25. #include "output.h"
  26. #include "vars.h"
  27. #include "server.h"
  28. #include "list.h"
  29. #include "term.h"
  30. #include "names.h"
  31. #include "ircaux.h"
  32. #include "input.h"
  33. #include "log.h"
  34. #include "hook.h"
  35. #include "dcc.h"
  36. #include "translat.h"
  37. #include "exec.h"
  38.  
  39.     Window    *to_window;
  40.     Screen    *current_screen = 0;
  41.     Screen    *main_screen;
  42.     Screen    *last_input_screen;
  43.  
  44. extern    int    in_help;    /* Used to suppress holding of help text */
  45. extern    char    *redirect_nick;
  46.  
  47. /* Our list of screens */
  48. Screen    *screen_list = NULL;
  49.  
  50. static    void    display_lastlog_lines();
  51. extern    void    close_all_server();
  52.  
  53. /*
  54.  * create_new_screen creates a new screen structure. with the help of
  55.  * this structure we maintain ircII windows that cross screen window
  56.  * boundaries.
  57.  */
  58. Screen    *
  59. create_new_screen()
  60. {
  61.     Screen    *new = NULL,
  62.         **list;
  63.     static    int    refnumber = 0;
  64.  
  65.     for (list = &screen_list; *list; list = &((*list)->next))
  66.     {
  67.         if (!(*list)->alive)
  68.         {
  69.             new = *list;
  70.             break;
  71.         }
  72.     }
  73.     if (!new)
  74.     {
  75.         new = (Screen *) malloc(sizeof(Screen));
  76.         new->screennum = ++refnumber;
  77.         new->next = screen_list;
  78.         if (screen_list)
  79.             screen_list->prev = new;
  80.         screen_list = new;
  81.     }
  82.     new->last_window_refnum = 1;
  83.     new->window_list = NULL;
  84.     new->window_list_end = NULL;
  85.     new->cursor_window = NULL;
  86.     new->current_window = NULL;
  87.     new->visible_windows = 0;
  88.     new->window_stack = NULL;
  89.     new->meta1_hit = new->meta2_hit = new->meta3_hit = new->meta4_hit = 0;
  90.     new->quote_hit = new->digraph_hit = new->inside_menu = 0;
  91.     new->buffer_pos = new->buffer_min_pos = 0;
  92.     new->input_buffer[0] = '\0';
  93.     new->fdout = 1;
  94.     new->fpout = stdout;
  95.     new->fdin = 0;
  96.     new->fpin = stdin;
  97.     new->alive = 1;
  98.     new->promptlist = NULL;
  99.     new->redirect_name = NULL;
  100.     new->redirect_token = NULL;
  101.     new->tty_name = (char *) 0;
  102.     new->li = 24;
  103.     new->co = 79;
  104.     new->redirect_server = -1;
  105. #ifdef _Windows
  106.     win_create_window(new);
  107. #endif
  108.     last_input_screen = new;
  109.     return new;
  110. }
  111.  
  112. /* 
  113.  * add_wait_prompt:  Given a prompt string, a function to call when
  114.  * the prompt is entered.. some other data to pass to the function,
  115.  * and the type of prompt..  either for a line, or a key, we add 
  116.  * this to the prompt_list for the current screen..  and set the
  117.  * input prompt accordingly.
  118.  */
  119. void
  120. add_wait_prompt(prompt, func, data, type)
  121.     char    *prompt;
  122.     void    (*func)();
  123.     char    *data;
  124.     int    type;
  125. {
  126.     WaitPrompt **AddLoc,
  127.            *New;
  128.  
  129.     New = (WaitPrompt *) new_malloc(sizeof(WaitPrompt));
  130.     New->prompt = NULL;
  131.     malloc_strcpy(&New->prompt, prompt);
  132.     New->data = NULL;
  133.     malloc_strcpy(&New->data, data);
  134.     New->type = type;
  135.     New->func = func;
  136.     New->next = NULL;
  137.     for (AddLoc = ¤t_screen->promptlist; *AddLoc;
  138.             AddLoc = &(*AddLoc)->next);
  139.     *AddLoc = New;
  140.     if (AddLoc == ¤t_screen->promptlist)
  141.         change_input_prompt(1);
  142. }
  143.  
  144. void
  145. set_current_screen(screen)
  146.     Screen    *screen;
  147. {
  148.     if (screen && screen->alive)
  149.         current_screen = screen;
  150.     else
  151.         current_screen = main_screen;
  152. }
  153.  
  154. /*
  155.  * window_redirect: Setting who to non null will cause IRCII to echo all
  156.  * commands and output from that server (including output generated by IRCII)
  157.  * to who.  Setting who to null disables this 
  158.  */
  159. void
  160. window_redirect(who, server)
  161.     char    *who;
  162.     int    server;
  163. {
  164.     define_big_buffer(buf);
  165.  
  166.     if (who)
  167.         sprintf(buf, "%04d%s", server, who);
  168.     else
  169.         sprintf(buf, "%04d#LAME", server);
  170.     malloc_strcpy(¤t_screen->redirect_token, buf);
  171.     malloc_strcpy(¤t_screen->redirect_name, who);
  172.     current_screen->redirect_server = server;
  173.     free_big_buffer(buf);
  174. }
  175.  
  176. extern    int
  177. check_screen_redirect(nick)
  178.     char    *nick;
  179. {
  180.     Screen    *screen,
  181.         *tmp_screen;
  182.     
  183.     for (screen = screen_list; screen; screen = screen->next)
  184.     {
  185.         if (!screen->redirect_token)
  186.             continue;
  187.         if (!strcmp(nick, screen->redirect_token))
  188.         {
  189.             tmp_screen = current_screen;
  190.             current_screen = screen;
  191.             window_redirect(NULL, from_server);
  192.             current_screen = tmp_screen;
  193.             return 1;
  194.         }
  195.     }
  196.     return 0;
  197. }
  198.  
  199. /* Old screens never die. They just fade away. */
  200.  
  201. #ifdef WINDOW_CREATE
  202. void
  203. kill_screen(screen)
  204.     Screen    *screen;
  205. {
  206.     Window    *window;
  207.  
  208.     if (main_screen == screen)
  209.     {
  210.         say("You may not kill the main screen");
  211.         return;
  212.     }
  213.     for (;(window = screen->window_list);)
  214.     {
  215.         screen->window_list = window->next;
  216.         add_to_invisible_list(window);
  217.     }
  218.  
  219.     if (last_input_screen == screen)
  220.         last_input_screen = screen_list;
  221.     screen->alive = 0;
  222. #ifdef _Windows
  223.     DestroyWindow(screen->hwnd);
  224. #else
  225.     if (screen->fdin)
  226.     {
  227.         close(screen->fdout);
  228.         close(screen->fdin);
  229.     }
  230. #endif
  231.     if (current_screen)
  232.         set_current_screen(current_screen);
  233. }
  234.  
  235. int
  236. is_main_screen(screen)
  237.     Screen    *screen;
  238. {
  239.     return (screen == main_screen);
  240. }
  241.  
  242. #else
  243.  
  244. int
  245. is_main_screen(screen)
  246.     Screen    *screen;
  247. {
  248.     return 1;
  249. }
  250.  
  251. #endif /* WINDOW_CREATE */
  252.  
  253.  
  254. /*
  255.  * scroll_window: Given a pointer to a window, this determines if that window
  256.  * should be scrolled, or the cursor moved to the top of the screen again, or
  257.  * if it should be left alone. 
  258.  */
  259. extern    void
  260. scroll_window(window)
  261.     Window    *window;
  262. {
  263.     if (dumb)
  264.         return;
  265.     if (window->cursor == window->display_size)
  266.     {
  267.         if (window->scroll)
  268.         {
  269.             int    scroll,
  270.             i;
  271.  
  272.             if ((scroll = get_int_var(SCROLL_LINES_VAR)) <= 0)
  273.                 scroll = 1;
  274.  
  275.             for (i = 0; i < scroll; i++)
  276.             {
  277.                 new_free (&window->top_of_display->line);
  278.                 window->top_of_display =
  279.                     window->top_of_display->next;
  280.             }
  281.             if (window->visible)
  282.             {
  283.                 if (term_scroll(window->top + window->menu.lines, window->top + window->menu.lines + window->cursor - 1, scroll))
  284.                 {
  285.                     if(current_screen->visible_windows == 1)
  286.                     {
  287.                         int    i;
  288.                         Window    *tmp;
  289.  
  290.             /*
  291.              * this method of sim-u-scroll seems to work fairly
  292.              * well. The penalty is that you can only have one
  293.              * window, and of course you can't use the scrollback
  294.              * buffer either. Or menus. Actually, this method
  295.              * really doesn't work very well at all anymore.
  296.              */
  297.                         tmp = current_screen->cursor_window;
  298.                         term_move_cursor(0, LI - 2);
  299.                         if (term_clear_to_eol())
  300.                             term_space_erase(0);
  301.                         term_cr();
  302.                         term_newline();
  303.                         for (i = 0; i < scroll; i++)
  304.                         {
  305.                             term_cr();
  306.                             term_newline();
  307.                         }
  308.                         update_window_status(window, 1);
  309.                         update_input(UPDATE_ALL);
  310.                         current_screen->cursor_window = tmp;
  311.                     }
  312.                     else
  313.                         redraw_window(window, 1);
  314.                 }
  315.                 window->cursor -= scroll;
  316.                 term_move_cursor(0, window->cursor + window->top + window->menu.lines);
  317.             }
  318.             else
  319.                 window->cursor -= scroll;
  320.         }
  321.         else
  322.         {
  323.             window->cursor = 0;
  324.             if (window->visible)
  325.                 term_move_cursor(0, window->top + window->menu.lines);
  326.         }
  327.     }
  328.     else if (window->visible && current_screen->cursor_window == window)
  329.     {
  330.         term_cr();
  331.         term_newline();
  332.     }
  333.     if (window->visible && current_screen->cursor_window)
  334.     {
  335.         if (term_clear_to_eol()) /* && !window->hold_mode && !window->hold_on_next_rite) */
  336.         {
  337.             term_space_erase(0);
  338.             term_cr();
  339.         }
  340.         term_flush();
  341.     }
  342. }
  343.  
  344. /* display_highlight: turns off and on the display highlight.  */
  345. static    char
  346. display_highlight(flag)
  347.     int    flag;
  348. {
  349.     static    int    highlight = OFF;
  350.  
  351.     fflush(current_screen->fpout);
  352.     if (flag == highlight)
  353.         return (flag);
  354.     switch (flag)
  355.     {
  356.     case ON:
  357.         highlight = ON;
  358.         if (get_int_var(INVERSE_VIDEO_VAR))
  359.             term_standout_on();
  360.         return (OFF);
  361.     case OFF:
  362.         highlight = OFF;
  363.         if (get_int_var(INVERSE_VIDEO_VAR))
  364.             term_standout_off();
  365.         return (ON);
  366.     case TOGGLE:
  367.         if (highlight == ON)
  368.         {
  369.             highlight = OFF;
  370.             if (get_int_var(INVERSE_VIDEO_VAR))
  371.                 term_standout_off();
  372.             return (ON);
  373.         }
  374.         else
  375.         {
  376.             highlight = ON;
  377.             if (get_int_var(INVERSE_VIDEO_VAR))
  378.                 term_standout_on();
  379.             return (OFF);
  380.         }
  381.     }
  382.     return flag;
  383. }
  384.  
  385. /* display_bold: turns off and on the display bolding.  */
  386. static    char
  387. display_bold(flag)
  388.     int    flag;
  389. {
  390.     static    int    bold = OFF;
  391.  
  392.     fflush(current_screen->fpout);
  393.     if (flag == bold)
  394.         return (flag);
  395.     switch (flag)
  396.     {
  397.     case ON:
  398.         bold = ON;
  399.         if (get_int_var(BOLD_VIDEO_VAR))
  400.             term_bold_on();
  401.         return (OFF);
  402.     case OFF:
  403.         bold = OFF;
  404.         if (get_int_var(BOLD_VIDEO_VAR))
  405.             term_bold_off();
  406.         return (ON);
  407.     case TOGGLE:
  408.         if (bold == ON)
  409.         {
  410.             bold = OFF;
  411.             if (get_int_var(BOLD_VIDEO_VAR))
  412.                 term_bold_off();
  413.             return (ON);
  414.         }
  415.         else
  416.         {
  417.             bold = ON;
  418.             if (get_int_var(BOLD_VIDEO_VAR))
  419.                 term_bold_on();
  420.             return (OFF);
  421.         }
  422.     }
  423.     return OFF;
  424. }
  425.  
  426. /*
  427.  * output_line prints the given string at the current screen position,
  428.  * performing adjustments for ^_, ^B, ^V, and ^O
  429.  */
  430. int
  431. output_line(str, result, startpos)
  432.     char    *str;
  433.     char    **result;
  434.     int    startpos;
  435. {
  436.     static    int    high = OFF, bold = OFF;
  437.     int    rev_tog, und_tog, bld_tog, all_off;
  438.     char    *ptr;
  439.     int    len;
  440.     int    written = 0;
  441.     char    c;
  442.     char    *original;
  443.  
  444.     original = str;
  445.     ptr = str;
  446.     display_highlight(high);
  447.     display_bold(bold);
  448.     /* do processing on the string, handle inverse and bells */
  449.     while (*ptr)
  450.     {
  451.         switch (*ptr)
  452.         {
  453.         case REV_TOG:
  454.         case UND_TOG:
  455.         case BOLD_TOG:
  456.         case ALL_OFF:
  457.             len = ptr - str;
  458.             written += len;
  459.             if (startpos)
  460.             {
  461.                 if (ptr - original > startpos)
  462.                 {
  463.                     str += len - (ptr - original - startpos);
  464.                     len = ptr - original - startpos;
  465.                     startpos = 0;
  466.                 }
  467.             }
  468.             if (written > CO)
  469.                 len = len - (written - CO);
  470.             if (!startpos)
  471. #ifdef _Windows
  472.                 output_to_window(str, len, current_screen->hwnd);
  473. #else
  474.                 fwrite(str, len, 1, current_screen->fpout);
  475. #endif
  476.             rev_tog = und_tog = bld_tog = all_off = 0;
  477.             do
  478.             {
  479.                 switch(*ptr)
  480.  
  481.                 {
  482.                 case REV_TOG:
  483.                     rev_tog = 1 - rev_tog;
  484.                     break;
  485.                 case UND_TOG:
  486.                     und_tog = 1 - und_tog;
  487.                     break;
  488.                 case BOLD_TOG:
  489.                     bld_tog = 1 - bld_tog;
  490.                     break;
  491.                 case ALL_OFF:
  492.                     all_off = 1;
  493.                     und_tog = rev_tog = bld_tog = 0;
  494.                     break;
  495.                 }
  496.             } while ((ptr[1] == REV_TOG || ptr[1] == UND_TOG ||
  497.                 ptr[1] == BOLD_TOG || ptr[1] == ALL_OFF) && ptr++);
  498.             if (all_off)
  499.             {
  500.                 if (!underline)
  501.                 {
  502.                     term_underline_off();
  503.                     underline = 1;
  504.                 }
  505.                 display_highlight(OFF);
  506.                 display_bold(OFF);
  507.                 high = 0;
  508.                 bold = 0;
  509.             }
  510.             if (und_tog && get_int_var(UNDERLINE_VIDEO_VAR))
  511.             {
  512.                 if ((underline = 1 - underline) != 0)
  513.                     term_underline_off();
  514.                 else
  515.                     term_underline_on();
  516.             }
  517.             if (rev_tog)
  518.             {
  519.                 high = display_highlight(TOGGLE);
  520.                 high = 1 - high;
  521.             }
  522.             if (bld_tog)
  523.             {
  524.                 bold = display_bold(TOGGLE);
  525.                 bold = 1 - bold;
  526.             }
  527.             str = ++ptr;
  528.             break;
  529.         case '\007':
  530.         /*
  531.          * same as above, except after we display everything
  532.          * so far, we beep the terminal 
  533.          */
  534.             c = *ptr;
  535.             *ptr = '\0';
  536.             len = strlen(str);
  537.             written += len;
  538.             if (startpos)
  539.             {
  540.                 if (ptr - original > startpos)
  541.                 {
  542.                     str += len - (ptr - original - startpos);
  543.                     len = ptr - original - startpos;
  544.                     startpos = 0;
  545.                 }
  546.             }
  547.             if (written > CO)
  548.                 len = len - (written - CO);
  549.             if (!startpos)
  550. #ifdef _Windows
  551.                 output_to_window(str, len, current_screen->hwnd);
  552. #else
  553.                 fwrite(str, len, 1, current_screen->fpout);
  554. #endif
  555.             term_beep();
  556.             *ptr = c;
  557.             str = ++ptr;
  558.             break;
  559.         default:
  560.             ptr++;
  561.             break;
  562.         }
  563.     }
  564.     if (result)
  565.         *result = str;
  566.     return written;
  567. }
  568.  
  569. /*
  570.  * rite: this routine displays a line to the screen adding bold facing when
  571.  * specified by ^Bs, etc.  It also does handles scrolling and paging, if
  572.  * SCROLL is on, and HOLD_MODE is on, etc.  This routine assumes that str
  573.  * already fits on one screen line.  If show is true, str is displayed
  574.  * regardless of the hold mode state.  If redraw is true, it is assumed we a
  575.  * redrawing the screen from the display_ip list, and we should not add what
  576.  * we are displaying back to the display_ip list again. 
  577.  *
  578.  * Note that rite sets display_highlight() to what it was at then end of the
  579.  * last rite().  Also, before returning, it sets display_highlight() to OFF.
  580.  * This way, between susequent rites(), you can be assured that the state of
  581.  * bold face will remain the same and the it won't interfere with anything
  582.  * else (i.e. status line, input line). 
  583.  */
  584. int
  585. rite(window, str, show, redraw, backscroll, logged)
  586.     Window    *window;
  587.     char    *str;
  588.     int    show,
  589.         redraw,
  590.         backscroll,
  591.         logged;
  592. {
  593.     static    int    high = OFF;
  594.     int    written = 0,
  595.         len;
  596.     Screen    *old_current_screen = current_screen;
  597.  
  598.     if (!backscroll && window->scrolled_lines)
  599.         window->new_scrolled_lines++;
  600. #if 0
  601.     if (window->hold_mode && window->hold_on_next_rite && !redraw && !backscroll && window->line_cnt >= window->display_size)
  602. #endif
  603.     if (window->hold_mode && window->hold_on_next_rite && !redraw && !backscroll)
  604.     {
  605.         /* stops output from going to the window */
  606.         window->hold_on_next_rite = 0;
  607.         hold_mode(window, ON, 1);
  608.         if (show)
  609.             return (1);
  610.     }
  611.     /*
  612.      * Don't need to worry about the current_screen if the window isn't
  613.      * visible, as hidden windows aren't attached to a screen anyway
  614.      */
  615.     if (window->visible)
  616.     {
  617.         old_current_screen = current_screen;
  618.         set_current_screen(window->screen);
  619.     }
  620.     if (!show && (hold_output(window) || hold_queue(window)) && !in_help && !redraw && !backscroll)
  621.         /* sends window output to the hold list for that window */
  622.         add_to_hold_list(window, str, logged);
  623.     else
  624.     {
  625.         if (!redraw && !backscroll)
  626.         {
  627.         /*
  628.          * This isn't a screen refresh, so add the line to the display
  629.          * list for the window 
  630.          */
  631.             if (window->scroll)
  632.                 scroll_window(window);
  633.             malloc_strcpy(&(window->display_ip->line), str);
  634.             window->display_ip->linetype = logged;
  635.             window->display_ip = window->display_ip->next;
  636.             if (!window->scroll)
  637.                 new_free(&window->display_ip->line);
  638.         }
  639.         if (window->visible)
  640.         {
  641.             /* make sure the cursor is in the appropriate window */
  642.             if (current_screen->cursor_window != window &&
  643.                     !redraw && !backscroll)
  644.             {
  645.                 current_screen->cursor_window = window;
  646.                 term_move_cursor(0, window->cursor +
  647.                     window->top + window->menu.lines);
  648.             }
  649.             written = output_line(str, &str, 0);
  650.             len = strlen(str);
  651.             written += len;
  652.             if (written > CO)
  653.                     len = len - (written - CO);
  654.             if (len > 0)
  655. #ifdef _Windows
  656.                 output_to_window(str, len, current_screen->hwnd);
  657. #else
  658.                 fwrite(str, len, 1, current_screen->fpout);
  659. #endif
  660.             if (term_clear_to_eol())
  661.                     term_space_erase(written);
  662.         }
  663.         else if (!(window->miscflags & WINDOW_NOTIFIED))
  664.         {
  665.             if (who_level & window->notify_level)
  666.             {
  667.                 window->miscflags |= WINDOW_NOTIFIED;
  668.                 if (window->miscflags & WINDOW_NOTIFY)
  669.                 {
  670.                     Window    *old_to_window;
  671.                     int    lastlog_level;
  672.  
  673.                     lastlog_level =
  674.                         set_lastlog_msg_level(LOG_CRAP);
  675.                     old_to_window = to_window;
  676.                     to_window = curr_scr_win;
  677.                     say("Activity in window %d",
  678.                         window->refnum);
  679.                     to_window = old_to_window;
  680.                     set_lastlog_msg_level(lastlog_level);
  681.                 }
  682.                 update_all_status();
  683.             }
  684.         }
  685.         if (!redraw && !backscroll)
  686.         {
  687.             window->cursor++;
  688.             window->line_cnt++;
  689.             if (window->scroll)
  690.             {
  691.                 if (window->line_cnt >= window->display_size)
  692.                 {
  693.                     window->hold_on_next_rite = 1;
  694.                     window->line_cnt = 0;
  695.                 }
  696.             }
  697.             else
  698.             {
  699.                 scroll_window(window);
  700.                 if (window->cursor == (window->display_size -1))
  701.                     window->hold_on_next_rite = 1;
  702.             }
  703.         }
  704.         else if (window->visible)
  705.         {
  706.             term_cr();
  707.             term_newline();
  708.         }
  709.         if (window->visible)
  710.         {
  711.             high = display_highlight(OFF);
  712.             term_flush();
  713.         }
  714.     }
  715.     if (window->visible)
  716.         set_current_screen(old_current_screen);
  717.     return (0);
  718. }
  719.  
  720. /*
  721.  * cursor_not_in_display: This forces the cursor out of the display by
  722.  * setting the cursor window to null.  This doesn't actually change the
  723.  * physical position of the cursor, but it will force rite() to reset the
  724.  * cursor upon its next call 
  725.  */
  726. void
  727. cursor_not_in_display()
  728. {
  729.     current_screen->cursor_window = NULL;
  730. }
  731.  
  732. /*
  733.  * cursor_in_display: this forces the cursor_window to be the
  734.  * current_screen->current_window. 
  735.  * It is actually only used in hold.c to trick the system into thinking the
  736.  * cursor is in a window, thus letting the input updating routines move the
  737.  * cursor down to the input line.  Dumb dumb dumb 
  738.  */
  739. void
  740. cursor_in_display()
  741. {
  742.     current_screen->cursor_window = curr_scr_win;
  743. }
  744.  
  745. /*
  746.  * is_cursor_in_display: returns true if the cursor is in one of the windows
  747.  * (cursor_window is not null), false otherwise 
  748.  */
  749. int
  750. is_cursor_in_display()
  751. {
  752.     if  (current_screen->cursor_window)
  753.         return (1);
  754.     else
  755.         return (0);
  756. }
  757.  
  758. void
  759. redraw_resized(window, Info, AnchorTop)
  760.     Window    *window;
  761.     ShrinkInfo Info;
  762.     int    AnchorTop;
  763. {
  764.     if (!AnchorTop)
  765.     {
  766.         if (Info.bottom < 0)
  767.             term_scroll(window->top+window->menu.lines+Info.bottom,
  768.                 window->top + window->menu.lines +
  769.                 window->display_size - 1,
  770.                 Info.bottom);
  771.         else if (Info.bottom)
  772.             term_scroll(window->top+window->menu.lines,
  773.                 window->top + window->menu.lines +
  774.                 window->display_size -1, Info.bottom);
  775.     }
  776. }
  777.  
  778. /*
  779.  * resize_display: After determining that the screen has changed sizes, this
  780.  * resizes all the internal stuff.  If the screen grew, this will add extra
  781.  * empty display entries to the end of the display list.  If the screen
  782.  * shrank, this will remove entries from the end of the display list.  By
  783.  * doing this, we try to maintain as much of the display as possible. 
  784.  *
  785.  * This has now been improved so that it returns enough information for
  786.  * redraw_resized to redisplay the contents of the window without having
  787.  * to redraw too much.
  788.  */
  789. ShrinkInfo
  790. resize_display(window)
  791.     Window    *window;
  792. {
  793.     int    cnt,
  794.         i;
  795.     Display *tmp, *pre_ip;
  796.     int    Wrapped = 0;
  797.     ShrinkInfo Result;
  798.  
  799.     Result.top = Result.bottom = 0;
  800.     Result.position = window->cursor;
  801.     if (dumb)
  802.     {
  803.         return Result;
  804.     }
  805.     if (!window->top_of_display)
  806.     {
  807.         window->top_of_display = (Display *)new_malloc(sizeof(Display));
  808.         window->top_of_display->line = NULL;
  809.         window->top_of_display->linetype = LT_UNLOGGED;
  810.         window->top_of_display->next = window->top_of_display;
  811.         window->display_ip = window->top_of_display;
  812.         window->old_size = 1;
  813.     }
  814.     /* cnt = size - window->display_size; */
  815.     cnt = window->display_size - window->old_size;
  816.     if (cnt > 0)
  817.     {
  818.         Display *new = NULL;
  819.  
  820.     /*
  821.      * screen got bigger: got to last display entry and link in new
  822.      * entries 
  823.      */
  824.         for (tmp = window->top_of_display, i = 0;
  825.             i < (window->old_size - 1);
  826.             i++, tmp = tmp->next);
  827.         for (i = 0; i < cnt; i++)
  828.         {
  829.             new = (Display *) new_malloc(sizeof(Display));
  830.             new->line = NULL;
  831.             new->linetype = LT_UNLOGGED;
  832.             new->next = tmp->next;
  833.             tmp->next = new;
  834.         }
  835.         if (window->display_ip == window->top_of_display &&
  836.             window->top_of_display->line)
  837.             window->display_ip = new;
  838.         Result.top = 0;
  839.         Result.bottom = cnt;
  840.         Result.position = 0;
  841.     }
  842.     else if (cnt < 0)
  843.  
  844.     {
  845.         Display *ptr;
  846.  
  847.     /*
  848.      * screen shrank: find last display entry we want to keep, and remove
  849.      * all after that point 
  850.      */
  851.         cnt = -cnt;
  852.         for (pre_ip = window->top_of_display;
  853.             pre_ip->next != window->display_ip;
  854.             pre_ip = pre_ip->next);
  855.         for (tmp = pre_ip->next, i =0; i < cnt; i++, tmp = ptr)
  856.         {
  857.             ptr = tmp->next;
  858.             if (tmp == window->top_of_display)
  859.  
  860.             {
  861.                 if (tmp->line)
  862.                     Wrapped = 1;
  863.                 window->top_of_display = ptr;
  864.             }
  865.             if (Wrapped)
  866.                 Result.top--;
  867.             else
  868.                 Result.bottom--;
  869.             new_free(&(tmp->line));
  870.             new_free(&tmp);
  871.         }
  872.         window->display_ip = pre_ip->next = tmp;
  873.         window->cursor += Result.top;
  874.         if (!window->scroll)
  875.         {
  876.             if (window->cursor == window->display_size)
  877.                 window->cursor = 0;
  878.             new_free(&window->display_ip->line);
  879.         }
  880.     }
  881.     window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
  882.     window->old_size = window->display_size;
  883.     return Result;
  884. }
  885.  
  886. /*
  887.  * recalculate_windows: this is called when the terminal size changes (as
  888.  * when an xterm window size is changed).  It recalculates the sized and
  889.  * positions of all the windows.  Currently, all windows are rebalanced and
  890.  * window size proportionality is lost 
  891.  */
  892. void
  893. recalculate_windows()
  894. {
  895.     int    base_size,
  896.     size,
  897.     top,
  898.     extra;
  899.     Window    *tmp;
  900.  
  901.     if (dumb || !current_screen->visible_windows)
  902.         return;
  903.     base_size = ((LI - 1) / current_screen->visible_windows) - 1;
  904.     extra = (LI - 1) - ((base_size + 1) * current_screen->visible_windows);
  905.     top = 0;
  906.     for (tmp = current_screen->window_list; tmp; tmp = tmp->next)
  907.     {
  908.         tmp->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
  909.         if (extra)
  910.         {
  911.             extra--;
  912.             size = base_size + 1;
  913.         }
  914.         else
  915.             size = base_size;
  916. #ifdef SCROLL_AFTER_DISPLAY
  917.         tmp->display_size = size - tmp->menu.lines - 1;
  918. #else
  919.         tmp->display_size = size - tmp->menu.lines;
  920. #endif /* SCROLL_AFTER_DISPLAY */
  921.         if (tmp->display_size<=0)
  922.             tmp->display_size = 1;
  923.         tmp->top = top;
  924.         tmp->bottom = top + size;
  925.         top += size + 1;
  926.     }
  927. }
  928.  
  929. /*
  930.  * clear_window: This clears the display list for the given window, or
  931.  * current window if null is given.  
  932.  */
  933. extern    void
  934. clear_window(window)
  935.     Window    *window;
  936. {
  937.     int    i,
  938.         cnt;
  939.  
  940.     if (dumb)
  941.         return;
  942.     if (window == NULL)
  943.         window = curr_scr_win;
  944.     erase_display(window);
  945.     term_move_cursor(0, window->top + window->menu.lines);
  946.     cnt = window->bottom - window->top - window->menu.lines;
  947.     for (i = 0; i < cnt; i++)
  948.     {
  949.         if (term_clear_to_eol())
  950.             term_space_erase(0);
  951.         term_newline();
  952.     }
  953.     term_flush();
  954. }
  955.  
  956. /* clear_all_windows: This clears all *visible* windows */
  957. extern    void
  958. clear_all_windows(unhold)
  959.     int    unhold;
  960. {
  961.     Window    *tmp;
  962.  
  963.     for (tmp = current_screen->window_list; tmp; tmp = tmp->next)
  964.     {
  965.         if (unhold)
  966.             hold_mode(tmp, OFF, 1);
  967.         clear_window(tmp);
  968.     }
  969. }
  970.  
  971. /*
  972.  * redraw_window: This redraws the display list for the given window. Some
  973.  * special considerations are made if you are just redrawing one window as
  974.  * opposed to using this routine to redraw the whole screen one window at a
  975.  * time 
  976.  *
  977.  * A negative value in just_one indicates not all of the window needs to
  978.  * be redrawn.
  979.  */
  980. void
  981. redraw_window(window, just_one)
  982.     Window    *window;
  983.     int    just_one;
  984. {
  985.     Display *tmp;
  986.     int    i;
  987.     int    StartPoint;
  988.     int    yScr;
  989.  
  990.     if (dumb || !window->visible)
  991.         return;
  992.     window = window ? window : curr_scr_win;
  993.     if (just_one < 0)
  994.  
  995.     {
  996.     /* This part of the window is scrolling into view */
  997.         StartPoint = -just_one;
  998.         just_one = 0;
  999.     }
  1000.     else
  1001.     {
  1002.         StartPoint = 0;
  1003.         if (window->scrolled_lines)
  1004.             display_lastlog_lines(window->scrolled_lines-window->display_size + 1, window->scrolled_lines, window);
  1005.     }
  1006.     if (window->menu.menu)
  1007.         ShowMenuByWindow(window, just_one ? SMF_ERASE : 0);
  1008.     if (window->scrolled_lines + StartPoint < window->display_size)
  1009.         yScr = window->scrolled_lines + StartPoint;
  1010.     else
  1011.         yScr = 0;
  1012.     term_move_cursor(0, window->top+window->menu.lines+yScr);
  1013.     /*
  1014.      * if (term_clear_to_eol())
  1015.      *    { term_space_erase(0); term_cr(); } 
  1016.      */
  1017.     for (tmp = window->top_of_display, i = 0; i < window->display_size-window->scrolled_lines; i++, tmp = tmp->next)
  1018.     {
  1019.         if (i < StartPoint)
  1020.             continue;
  1021.         if (tmp->line)
  1022.             rite(window, tmp->line, 1, 1, 0, 0);
  1023.         else
  1024.         {
  1025.             if (just_one)
  1026.             {
  1027.                 if (term_clear_to_eol())
  1028.                     term_space_erase(0);
  1029.             }
  1030.             term_newline();
  1031.         }
  1032.     }
  1033.     term_flush();
  1034. }
  1035.  
  1036. /*
  1037.  * recalculate_window_positions: This runs through the window list and
  1038.  * re-adjusts the top and bottom fields of the windows according to their
  1039.  * current positions in the window list.  This doesn't change any sizes of
  1040.  * the windows 
  1041.  */
  1042. extern    void
  1043. recalculate_window_positions()
  1044. {
  1045.     Window    *tmp;
  1046.     int    top;
  1047.  
  1048.     top = 0;
  1049.     for (tmp = current_screen->window_list; tmp; tmp = tmp->next)
  1050.     {
  1051.         tmp->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
  1052.         tmp->top = top;
  1053.         tmp->bottom = top + tmp->display_size + tmp->menu.lines;
  1054.         top += tmp->display_size + tmp->menu.lines + 1;
  1055.     }
  1056. }
  1057.  
  1058. /*
  1059.  * redraw_all_windows: This basically clears and redraws the entire display
  1060.  * portion of the screen.  All windows and status lines are draws.  This does
  1061.  * nothing for the input line of the screen.  Only visible windows are drawn 
  1062.  */
  1063. void
  1064. redraw_all_windows()
  1065. {
  1066.     Window    *tmp;
  1067.  
  1068.     if (dumb)
  1069.         return;
  1070.     for (tmp = current_screen->window_list; tmp; tmp = tmp->next)
  1071.         tmp->update |= REDRAW_STATUS | REDRAW_DISPLAY_FAST;
  1072. }
  1073.  
  1074. #define    MAXIMUM_SPLITS    40
  1075. char    **
  1076. split_up_line(str)
  1077.     char    *str;
  1078. {
  1079.     static    char    *output[MAXIMUM_SPLITS] =
  1080.     { 
  1081.         NULL, NULL, NULL, NULL,
  1082.         NULL, NULL, NULL, NULL,
  1083.         NULL, NULL, NULL, NULL,
  1084.         NULL, NULL, NULL, NULL,
  1085.         NULL, NULL, NULL, NULL,
  1086.         NULL, NULL, NULL, NULL,
  1087.         NULL, NULL, NULL, NULL,
  1088.         NULL, NULL, NULL, NULL,
  1089.         NULL, NULL, NULL, NULL,
  1090.         NULL, NULL, NULL, NULL
  1091.     };
  1092.     define_big_buffer(buffer);
  1093.     unsigned char *ptr;
  1094.     char    *cont_ptr,
  1095.         *cont = NULL,
  1096.         *temp = NULL,
  1097.         c;
  1098.     int    pos = 0,
  1099.         col = 0,
  1100.         nd_cnt = 0,
  1101.         word_break = 0,
  1102.         start = 0,
  1103.         i,
  1104.         len,
  1105.         indent = 0,
  1106.         beep_cnt = 0,
  1107.         beep_max,
  1108.         tab_cnt = 0,
  1109.         tab_max,
  1110.         line = 0;
  1111.  
  1112.     bzero(buffer, sizeof(buffer));
  1113.     for (i = 0; i < MAXIMUM_SPLITS; i++)
  1114.         new_free(&output[i]);
  1115.     if (!*str)
  1116.         malloc_strcpy(&str, " ");    /* special case to make blank lines show up */
  1117.  
  1118.     beep_max = get_int_var(BEEP_VAR) ? get_int_var(BEEP_MAX_VAR) : -1;
  1119.     tab_max = get_int_var(TAB_VAR) ? get_int_var(TAB_MAX_VAR) : -1;
  1120.     for (ptr = (u_char *) str; *ptr && (pos < BIG_BUFFER_SIZE - 8); ptr++)
  1121.     {
  1122.         if (translation)
  1123.             *ptr = transToClient[*ptr];
  1124.         if (*ptr <= 32)
  1125.         {
  1126.             switch (*ptr)
  1127.             {
  1128.             case '\007':    /* bell */
  1129.                 if (beep_max == -1)
  1130.                 {
  1131.                     buffer[pos++] = REV_TOG;
  1132.                     buffer[pos++] = (*ptr & 127) | 64;
  1133.                     buffer[pos++] = REV_TOG;
  1134.                     nd_cnt += 2;
  1135.                     col++;
  1136.                 }
  1137.                 else if (!beep_max || (++beep_cnt <= beep_max))
  1138.                 {
  1139.                     buffer[pos++] = *ptr;
  1140.                     nd_cnt++;
  1141.                     col++;
  1142.                 }
  1143.                 break;
  1144.             case '\011':    /* tab */
  1145.                 if (tab_max && (++tab_cnt > tab_max))
  1146.                 {
  1147.                     buffer[pos++] = REV_TOG;
  1148.                     buffer[pos++] = (*ptr & 127) | 64;
  1149.                     buffer[pos++] = REV_TOG;
  1150.                     nd_cnt += 2;
  1151.                     col++;
  1152.                 }
  1153.                 else
  1154.                 {
  1155.                     if (indent == 0)
  1156.                         indent = -1;
  1157.                     len = 8 - (col % 8);
  1158.                     word_break = pos;
  1159.                     for (i = 0; i < len; i++)
  1160.                         buffer[pos++] = ' ';
  1161.                     col += len;
  1162.                 }
  1163.                 break;
  1164.             case ' ':    /* word break */
  1165.                 if (indent == 0)
  1166.                     indent = -1;
  1167.                 word_break = pos;
  1168.                 buffer[pos++] = *ptr;
  1169.                 col++;
  1170.                 break;
  1171.             case UND_TOG:
  1172.             case ALL_OFF:
  1173.             case REV_TOG:
  1174.             case BOLD_TOG:
  1175.                 buffer[pos++] = *ptr;
  1176.                 nd_cnt++;
  1177.                 break;
  1178.             default:    /* Anything else, make it displayable */
  1179.                 if (indent == -1)
  1180.                     indent = pos - nd_cnt;
  1181.                 buffer[pos++] = REV_TOG;
  1182.                 buffer[pos++] = (*ptr & 127) | 64;
  1183.                 buffer[pos++] = REV_TOG;
  1184.                 nd_cnt += 2;
  1185.                 col++;
  1186.                 break;
  1187.             }
  1188.         }
  1189.         else
  1190.         {
  1191.             if (indent == -1)
  1192.                 indent = pos - nd_cnt;
  1193.             buffer[pos++] = *ptr;
  1194.             col++;
  1195.         }
  1196.         if (pos == BIG_BUFFER_SIZE)
  1197.             *ptr = '\0';
  1198.         if (col >= CO)
  1199.         {
  1200.             /* one big long line, no word breaks */
  1201.             if (word_break == 0)
  1202.                 word_break = pos - (col - CO);
  1203.             c = buffer[word_break];
  1204.             buffer[word_break] = '\0';
  1205.             if (cont)
  1206.             {
  1207.                 malloc_strcpy(&temp, cont);
  1208.                 malloc_strcat(&temp, &(buffer[start]));
  1209.             }
  1210.             else
  1211.                 malloc_strcpy(&temp, &(buffer[start]));
  1212.             malloc_strcpy(&output[line++], temp);
  1213.             buffer[word_break] = c;
  1214.             start = word_break;
  1215.             word_break = 0;
  1216.             while (buffer[start] == ' ')
  1217.                 start++;
  1218.             if (start > pos)
  1219.                 start = pos;
  1220.             if (!(cont_ptr = get_string_var(CONTINUED_LINE_VAR)))
  1221.                     
  1222.                 cont_ptr = empty_string;
  1223.             if (get_int_var(INDENT_VAR) && (indent < CO / 3))
  1224.             {
  1225.         /*
  1226.          * INDENT thanks to Carlo "lynx" v. Loesch
  1227.          * - hehe, nice to see this is still here... -lynx 91
  1228.          */
  1229.                 if (!cont)
  1230.                 {
  1231.                     if ((len = strlen(cont_ptr)) > indent)
  1232.                     {
  1233.                         cont = (char *) new_malloc(len
  1234.                             + 1);
  1235.                         strcpy(cont, cont_ptr);
  1236.                     }
  1237.                     else
  1238.                     {
  1239.                         cont = (char *)
  1240.                             new_malloc(indent + 1);
  1241.                         strcpy(cont, cont_ptr);
  1242.                         for (i = len; i < indent; i++)
  1243.                             cont[i] = ' ';
  1244.                         cont[indent] = '\0';
  1245.                     }
  1246.                 }
  1247.             }
  1248.             else
  1249.                 malloc_strcpy(&cont, cont_ptr);
  1250.             col = strlen(cont) + (pos - start);
  1251.         }
  1252.     }
  1253.     buffer[pos] = '\0';
  1254.     if (buffer[start])
  1255.     {
  1256.         if (cont)
  1257.         {
  1258.             malloc_strcpy(&temp, cont);
  1259.             malloc_strcat(&temp, &(buffer[start]));
  1260.         }
  1261.         else
  1262.             malloc_strcpy(&temp, &(buffer[start]));
  1263.         malloc_strcpy(&output[line++], temp);
  1264.     }
  1265.     new_free(&cont);
  1266.     new_free(&temp);
  1267.     free_big_buffer(buffer);
  1268.     return output;
  1269. }
  1270.  
  1271. /*
  1272.  * add_to_window: adds the given string to the display.  No kidding. This
  1273.  * routine handles the whole ball of wax.  It keeps track of what's on the
  1274.  * screen, does the scrolling, everything... well, not quite everything...
  1275.  * The CONTINUED_LINE idea thanks to Jan L. Peterson (jlp@hamblin.byu.edu)  
  1276.  *
  1277.  * At least it used to. Now most of this is done by split_up_line, and this
  1278.  * function just dumps it onto the screen. This is because the scrollback
  1279.  * functions need to be able to figure out how to split things up too.
  1280.  */
  1281. static    void
  1282. add_to_window(window, str)
  1283.     Window    *window;
  1284.     char    *str;
  1285. {
  1286.     int flag;
  1287.     Screen *old_current_screen;
  1288.  
  1289.     add_to_log(window->log_fp, str);
  1290.     flag = do_hook(WINDOW_LIST, "%u %s", window->refnum, str);
  1291.     add_to_lastlog(window, str);
  1292.  
  1293.     if (flag)
  1294.     {
  1295.         char    **lines;
  1296.         int    logged;
  1297.  
  1298.         display_highlight(OFF);
  1299.         display_bold(OFF);
  1300.         strmcat(str, global_all_off, BIG_BUFFER_SIZE - 1);
  1301.         logged = islogged(window);
  1302.         old_current_screen = current_screen;
  1303.         set_win_scr(window);
  1304.         lines = split_up_line(str);
  1305.         set_current_screen(old_current_screen);
  1306.         for (; *lines; lines++)
  1307.         {
  1308.             rite(window, *lines, 0, 0, 0, logged);
  1309.             if (logged == 1)
  1310.                 logged = 2;
  1311.         }
  1312.         term_flush();
  1313.     }
  1314. }
  1315.  
  1316. Window
  1317. *get_output_window()
  1318. {
  1319.     int    flag;
  1320.     Window    *tmp;
  1321.     TravInfo ti;
  1322.  
  1323.     if ((who_level == LOG_CURRENT) && (curr_scr_win->server == from_server))
  1324.         return curr_scr_win;
  1325.     if (to_window)
  1326.         return to_window;
  1327.     if (who_from)
  1328.     {
  1329.         flag = 1;
  1330.         while ((tmp = traverse_all_windows(&flag, &ti)) != NULL)
  1331.         {
  1332.             if (tmp->current_channel &&
  1333.                 !my_stricmp(who_from, tmp->current_channel) &&
  1334.                 tmp->server == from_server)
  1335.                 return tmp;
  1336.             if (tmp->query_nick &&
  1337.                 (((who_level==LOG_MSG || who_level==LOG_NOTICE) &&
  1338.                 !my_stricmp(who_from, tmp->query_nick) &&
  1339.                 from_server == tmp->server) ||
  1340.                 (who_level==LOG_DCC &&
  1341.                 (*tmp->query_nick=='=' || *tmp->query_nick=='@') &&
  1342.                 my_stricmp(who_from, tmp->query_nick+1) == 0)))
  1343.                 return tmp;
  1344.         }
  1345.         flag = 1;
  1346.         while ((tmp = traverse_all_windows(&flag, &ti)) != NULL)
  1347.         {
  1348.             if (from_server == tmp->server &&
  1349.                 find_in_list(&(tmp->nicks), who_from, !USE_WILDCARDS))
  1350.                     return tmp;
  1351.         }
  1352.     }
  1353.     flag = 1;
  1354.     while ((tmp = traverse_all_windows(&flag, &ti)) != NULL)
  1355.     {
  1356.         if (((from_server == tmp->server) || (from_server == -1)) &&
  1357.             (who_level & tmp->window_level))
  1358.             return tmp;
  1359.     }
  1360.     if (from_server == curr_scr_win->server)
  1361.         return curr_scr_win;
  1362.     else
  1363.     {
  1364.         flag = 1;
  1365.         while ((tmp = traverse_all_windows(&flag, &ti)) != NULL)
  1366.         {
  1367.             if (tmp->server == from_server)
  1368.                 return tmp;
  1369.         }
  1370.     }
  1371.     return curr_scr_win;
  1372. }
  1373.  
  1374. /*
  1375.  * add_to_screen: This adds the given null terminated buffer to the screen.
  1376.  * That is, it determines which window the information should go to, which
  1377.  * lastlog the information should be added to, which log the information
  1378.  * should be sent to, etc 
  1379.  */
  1380. void
  1381. add_to_screen(buffer)
  1382.     char    *buffer;
  1383. {
  1384.     /* Handles output redirection first */
  1385.     if (current_screen->redirect_name &&
  1386.         from_server == current_screen->redirect_server)
  1387.     {
  1388.         int    i;
  1389.  
  1390. #ifndef _Windows
  1391.         if (*current_screen->redirect_name == '%')
  1392.         {    /* redirection to a process */
  1393.             if (is_number(current_screen->redirect_name + 1))
  1394.                 i = atoi(current_screen->redirect_name + 1);
  1395.             else
  1396.                 i = logical_to_index(current_screen->redirect_name
  1397.                 + 1);
  1398.             if (is_process_running(i))
  1399.                 text_to_process(i, buffer, 0);
  1400.         }
  1401.         else
  1402. #endif /* _Windows */
  1403.         if (*current_screen->redirect_name == '=')
  1404.             dcc_message_transmit(current_screen->redirect_name + 1,
  1405.                 buffer, DCC_CHAT, 0);
  1406.         /*
  1407.          * shouldn't this be a NOTICE?  -lynx
  1408.          * agreed - phone, jan 1993
  1409.          */
  1410.         else
  1411.             send_to_server("PRIVMSG %s :%s",
  1412.                 current_screen->redirect_name, buffer);
  1413.     }
  1414.     if (dumb)
  1415.     {
  1416.         add_to_lastlog(curr_scr_win, buffer);
  1417.         if (do_hook(WINDOW_LIST, "%u %s", curr_scr_win->refnum, buffer))
  1418.             puts(buffer);
  1419.         fflush(current_screen->fpout);
  1420.         return;
  1421.     }
  1422.     if (in_window_command)
  1423.         update_all_windows();
  1424.     add_to_window(get_output_window(), buffer);
  1425. }
  1426.  
  1427. /*
  1428.  * update_all_windows: This goes through each visible window and draws the
  1429.  * necessary portions according the the update field of the window. 
  1430.  */
  1431. void
  1432. update_all_windows()
  1433. {
  1434.     Window    *tmp;
  1435.     int    fast_window,
  1436.         full_window,
  1437.         r_status,
  1438.         u_status;
  1439.  
  1440.     for (tmp = current_screen->window_list; tmp; tmp = tmp->next)
  1441.     {
  1442.         if (tmp->display_size != tmp->old_size)
  1443.             resize_display(tmp);
  1444.         if (tmp->update)
  1445.         {
  1446.             fast_window = tmp->update & REDRAW_DISPLAY_FAST;
  1447.             full_window = tmp->update & REDRAW_DISPLAY_FULL;
  1448.             r_status = tmp->update & REDRAW_STATUS;
  1449.             u_status = tmp->update & UPDATE_STATUS;
  1450.             if (full_window)
  1451.                 redraw_window(tmp, 1);
  1452.             else if (fast_window)
  1453.                 redraw_window(tmp, 0);
  1454.             if (r_status)
  1455.                 update_window_status(tmp, 1);
  1456.             else if (u_status)
  1457.                 update_window_status(tmp, 0);
  1458.         }
  1459.         tmp->update = 0;
  1460.     }
  1461.     for (tmp = invisible_list; tmp; tmp = tmp->next)
  1462.     {
  1463.         if (tmp->display_size != tmp->old_size)
  1464.             resize_display(tmp);
  1465.         tmp->update = 0;
  1466.     }
  1467.     update_input(UPDATE_JUST_CURSOR);
  1468.     term_flush();
  1469. }
  1470.  
  1471. /*
  1472.  * create_refnum: this generates a reference number for a new window that is
  1473.  * not currently is use by another window.  A refnum of 0 is reserved (and
  1474.  * never returned by this routine).  Using a refnum of 0 in the message_to()
  1475.  * routine means no particular window (stuff goes to CRAP) 
  1476.  */
  1477. static    u_int
  1478. create_refnum()
  1479. {
  1480.     unsigned int    new_refnum = 1;
  1481.     Window    *tmp;
  1482.     int    done = 0,
  1483.         flag;
  1484.     TravInfo ti;
  1485.  
  1486.     while (!done)
  1487.     {
  1488.         done = 1;
  1489.         if (new_refnum == 0)
  1490.             new_refnum++;
  1491.  
  1492.         flag = 1;
  1493.         while ((tmp = traverse_all_windows(&flag, &ti)) != NULL)
  1494.         {
  1495.             if (tmp->refnum == new_refnum)
  1496.             {
  1497.                 done = 0;
  1498.                 new_refnum++;
  1499.                 break;
  1500.             }
  1501.         }
  1502.     }
  1503.     return (new_refnum);
  1504. }
  1505.  
  1506. /*
  1507.  * new_window: This creates a new window on the screen.  It does so by either
  1508.  * splitting the current window, or if it can't do that, it splits the
  1509.  * largest window.  The new window is added to the window list and made the
  1510.  * current window 
  1511.  */
  1512. Window    *
  1513. new_window()
  1514. {
  1515.     Window    *new;
  1516.     static    int    no_screens = 1;
  1517.  
  1518.     if (no_screens)
  1519.  
  1520.     {
  1521.         set_current_screen(create_new_screen());
  1522.         main_screen = current_screen;
  1523.         no_screens = 0;
  1524.     }
  1525.     if (dumb && (current_screen->visible_windows == 1))
  1526.         return NULL;
  1527.     new = (Window *) new_malloc(sizeof(Window));
  1528.     new->refnum = create_refnum();
  1529.     if (curr_scr_win)
  1530.         new->server = curr_scr_win->server;
  1531.     else
  1532.         new->server = primary_server;
  1533.     new->line_cnt = 0;
  1534. #ifndef PHONE    /* I hate having new windows with level ALL automatically */
  1535.     if (current_screen->visible_windows == 0)
  1536.         new->window_level = LOG_ALL;
  1537.     else
  1538. #endif
  1539.         new->window_level = LOG_NONE;
  1540.     new->hold_mode = get_int_var(HOLD_MODE_VAR);
  1541.     new->scroll = get_int_var(SCROLL_VAR);
  1542.     new->lastlog_head = 0;
  1543.     new->lastlog_tail = 0;
  1544.     new->nicks = 0;
  1545.     new->lastlog_level = real_lastlog_level();
  1546.     new->name = 0;
  1547.     new->prompt = 0;
  1548.     new->lastlog_size = 0;
  1549.     new->held = OFF;
  1550.     new->last_held = OFF;
  1551.     new->current_channel = 0;
  1552.     new->query_nick = 0;
  1553.     new->hold_on_next_rite = 0;
  1554.     new->status_line = 0;
  1555.     new->top_of_display = 0;
  1556.     new->display_ip = 0;
  1557.     new->display_size = 1;
  1558.     new->old_size = 1;
  1559.     new->hold_head = 0;
  1560.     new->hold_tail = 0;
  1561.     new->held_lines = 0;
  1562.     new->scrolled_lines = 0;
  1563.     new->new_scrolled_lines = 0;
  1564.     new->next = 0;
  1565.     new->prev = 0;
  1566.     new->cursor = 0;
  1567.     new->visible = 1;
  1568.     new->screen = current_screen;
  1569.     new->waiting_channel = 0;
  1570.     new->logfile = 0;
  1571.     new->log = 0;
  1572.     new->log_fp = 0;
  1573.     new->miscflags = 0;
  1574.     new->update = 0;
  1575.     new->menu.lines = 0;
  1576.     new->menu.menu = 0;
  1577.     new->notify_level = real_notify_level();
  1578.     resize_display(new);
  1579.     if (add_to_window_list(new))
  1580.         set_current_window(new);
  1581.     term_flush();
  1582.     return (new);
  1583. }
  1584.  
  1585. #ifdef WINDOW_CREATE
  1586. extern    Window    *
  1587. create_additional_screen()
  1588. {
  1589.     Window    *win;
  1590.     Screen    *screen,
  1591.         *oldscreen;
  1592.     char    *displayvar,
  1593.         *termvar;
  1594.     int    screen_type = ST_NOTHING;
  1595.  
  1596. #ifdef _Windows
  1597.     oldscreen = current_screen;
  1598.     set_current_screen(create_new_screen());
  1599.     win = new_window();
  1600.     (void) refresh_screen(0, NULL);
  1601.     set_current_screen(oldscreen);
  1602.     return win;
  1603.  
  1604. #else /* _Windows */
  1605.     define_big_buffer(PipeName);
  1606.     struct    sockaddr_un *sockaddr = (struct sockaddr_un *) PipeName,
  1607.             NewSock;
  1608.     int    NsZ;
  1609.     int    s;
  1610.     fd_set    fd_read;
  1611.     struct    timeval    timeout;
  1612.     pid_t    child;
  1613.     int    old_timeout;
  1614. #define IRCXTERM_MAX 10
  1615.     char    *ircxterm[IRCXTERM_MAX];
  1616.     char    *ircxterm_env;
  1617.     char    *xterm = (char *) 0;
  1618.     int    ircxterm_num;
  1619.     char    *p, *q;
  1620.     int    i;
  1621.  
  1622. #ifdef DAEMON_UID
  1623.     if (DAEMON_UID == getuid())
  1624.     {
  1625.         say("you are not permitted to use WINDOW CREATE");
  1626.         free_big_buffer(PipeName);
  1627.         return (Window *) 0;
  1628.     }
  1629. #endif
  1630.  
  1631.     ircxterm_num = 0;
  1632.     p = ircxterm_env = getenv("IRCXTERM");
  1633.     if (p)
  1634.     {
  1635.         q = ircxterm_env + strlen(ircxterm_env);
  1636.         while (p < q)
  1637.         {
  1638.             while (':' == *p)
  1639.                 p++;
  1640.             if ('\0' == *p)
  1641.                 break;
  1642.             ircxterm[ircxterm_num++] = p;
  1643.             while (':' != *p && '\0' != *p)
  1644.                 p++;
  1645.             if (':' == *p)
  1646.             {
  1647.                 *p = '\0';
  1648.                 p++;
  1649.             }
  1650.         }
  1651.     }
  1652.     else
  1653.     {
  1654.         ircxterm[ircxterm_num] = "xterm";
  1655.         ircxterm_num++;
  1656.     }
  1657.  
  1658.     /*
  1659.      * Environment variable STY has to be set for screen to work..  so it is
  1660.      * the best way to check screen..  regardless of what TERM is, the 
  1661.      * execpl() for screen won't just open a new window if STY isn't set,
  1662.      * it will open a new screen process, and run the wserv in its first
  1663.      * window, not what we want...  -phone
  1664.      */
  1665.     if (0 != getenv("STY"))
  1666.     {
  1667.         screen_type = ST_SCREEN;
  1668.     }
  1669.     else if ((char *) 0 != (displayvar = getenv("DISPLAY")))
  1670.     {
  1671.         if ((char *) 0 == (termvar = getenv("TERM")))
  1672.         {
  1673.             say("I don't know how to create new windows for this terminal");
  1674.             free_big_buffer(PipeName);
  1675.             return (Window *) 0;
  1676.         }
  1677.         screen_type = ST_XTERM;
  1678.         if (0 == strncmp(termvar, "sun", 3))
  1679.         {
  1680.             xterm = "xterm";
  1681.         }
  1682.         else
  1683.         {
  1684.             for(; *termvar; termvar++)
  1685.             {
  1686.                 for (i = 0; i < ircxterm_num; i++)
  1687.                 {
  1688.                     if (!strncmp(termvar, ircxterm[i], strlen(ircxterm[i])))
  1689.                     {
  1690.                         screen_type = ST_XTERM;
  1691.                         malloc_strcpy(&xterm, ircxterm[i]);
  1692.                         termvar = empty_string;
  1693.                         break;
  1694.                     }
  1695.                 }
  1696.             }
  1697.         }
  1698.     }
  1699.  
  1700.     if (screen_type == ST_NOTHING)
  1701.     {
  1702.         say("I don't know how to create new windows for this terminal");
  1703.         free_big_buffer(PipeName);
  1704.         return (Window *) 0;
  1705.     }
  1706.     say("Opening new screen...");
  1707.     sprintf(PipeName + sizeof(sockaddr->sun_family), "/tmp/irc_%08d", getpid());
  1708.     sockaddr->sun_family = AF_UNIX;
  1709.     s = socket(AF_UNIX, SOCK_STREAM, 0);
  1710.     bind(s, (struct sockaddr *) sockaddr, strlen(sockaddr->sun_path) + sizeof(sockaddr->sun_family));
  1711.     listen(s, 1);
  1712.     oldscreen = current_screen;
  1713.     set_current_screen(create_new_screen());
  1714.     if (0 == (child = fork()))
  1715.     {
  1716.         setuid(getuid());
  1717.         setgid(getgid());
  1718.     /*
  1719.      * Unlike most other cases, it is important here to close down
  1720.      * *ALL* unneeded file descriptors. Failure to do so can cause
  1721.      * Things like server and DCC connections to fail to close on
  1722.      * request. This isn't a problem with "screen", but is with X.
  1723.      */
  1724.         close(s);
  1725.         for (screen = screen_list; screen && screen != current_screen;
  1726.                 screen = screen->next)
  1727.             if (screen->alive && screen->fdin != 0)
  1728.                 new_close(screen->fdin);
  1729.         close_all_dcc();
  1730.         close_all_exec();
  1731.         close_all_server();
  1732.         if (screen_type == ST_SCREEN)
  1733.             execlp("screen", "screen", WSERV_PATH,
  1734.                 sockaddr->sun_path, 0);
  1735.         else if (screen_type == ST_XTERM)
  1736.         {
  1737.             int    lines,
  1738.                 columns,
  1739.                 i = 0;
  1740.             char    geom[20],
  1741.                 *args[64],
  1742.                 *s,
  1743.                 *t,
  1744.                 *opts = NULL;
  1745.  
  1746.             copy_window_size(&lines, &columns);
  1747.             sprintf(geom, "%dx%d", columns, lines);
  1748.             args[i++] = xterm;
  1749.             args[i++] = "-geom";
  1750.             args[i++] = geom;
  1751.             if ((s = get_string_var(XTERM_OPTIONS_VAR)) != NULL)
  1752.             {
  1753.                 malloc_strcpy(&opts, s);
  1754.                 while ((t = (char *) strtok(opts," ")) != NULL)
  1755.                 {
  1756.                     args[i++] = t;
  1757.                     opts = NULL;
  1758.                 }
  1759.             }
  1760.             args[i++] = "-e";
  1761.             args[i++] = WSERV_PATH;
  1762.             args[i++] = sockaddr->sun_path;
  1763.             args[i] = NULL;
  1764.             execvp(xterm, args);
  1765.         }
  1766.         exit(1);
  1767.     }
  1768.     NsZ = sizeof(NewSock);
  1769.     FD_ZERO(&fd_read);
  1770.     FD_SET(s, &fd_read);
  1771.     timeout.tv_sec = (time_t) 5;
  1772.  
  1773.     /* using say(), yell() can be bad in this next section of code. */
  1774.  
  1775.     switch (select(NFDBITS , &fd_read, NULL, NULL, &timeout))
  1776.     {
  1777.     case -1:
  1778.     case 0:
  1779.         close(s);
  1780.         unlink(sockaddr->sun_path);
  1781.         kill_screen(current_screen);
  1782.         kill(child, SIGKILL);
  1783.         last_input_screen = oldscreen;
  1784.         set_current_screen(oldscreen);
  1785.         free_big_buffer(PipeName);
  1786.         return (Window *) 0;
  1787.         break;
  1788.     default:
  1789.         current_screen->fdin = current_screen->fdout =
  1790.             accept(s, (struct sockaddr *) &NewSock, &NsZ);
  1791.         if (current_screen->fdin < 0)
  1792.             return (Window *) 0;
  1793.         current_screen->fpin = current_screen->fpout =
  1794.             fdopen(current_screen->fdin, "r+");
  1795.         close(s);
  1796.         unlink(sockaddr->sun_path);
  1797.         old_timeout = dgets_timeout(5);
  1798.         if (0 > dgets(buffer, BIG_BUFFER_SIZE, current_screen->fdin))
  1799.         {
  1800.             close(current_screen->fdin);
  1801.             kill_screen(current_screen);
  1802.             kill(child, SIGKILL);
  1803.             last_input_screen = oldscreen;
  1804.             set_current_screen(oldscreen);
  1805.             (void) dgets_timeout(old_timeout);
  1806.             free_big_buffer(PipeName);
  1807.             return (Window *) 0;
  1808.         }
  1809.         else
  1810.             malloc_strcpy(¤t_screen->tty_name, buffer);
  1811.         win = new_window();
  1812.         (void) refresh_screen(0, NULL);
  1813.         set_current_screen(oldscreen);
  1814.         (void) dgets_timeout(old_timeout);
  1815.         free_big_buffer(PipeName);
  1816.         return win;
  1817.         break;
  1818.     }
  1819.     free_big_buffer(PipeName);
  1820.     return NULL;
  1821. #endif /* _Windows */
  1822. }
  1823. #endif /* WINDOW_CREATE */
  1824.  
  1825. static    char    *
  1826. next_line_back(window)
  1827. Window    *window;
  1828. {
  1829.     static    int    row;
  1830.     static    Lastlog    *LogLine;
  1831.     char    **TheirLines;
  1832.     static    char    *ScreenLines[MAXIMUM_SPLITS] =
  1833.     { 
  1834.         NULL, NULL, NULL, NULL,
  1835.         NULL, NULL, NULL, NULL,
  1836.         NULL, NULL, NULL, NULL,
  1837.         NULL, NULL, NULL, NULL,
  1838.         NULL, NULL, NULL, NULL,
  1839.         NULL, NULL, NULL, NULL,
  1840.         NULL, NULL, NULL, NULL,
  1841.         NULL, NULL, NULL, NULL,
  1842.         NULL, NULL, NULL, NULL,
  1843.         NULL, NULL, NULL, NULL
  1844.     };
  1845.  
  1846.     if (window)
  1847.     {
  1848.         LogLine = window->lastlog_head;
  1849.         row = -1;
  1850.     }
  1851.     if (row <= 0)
  1852.     {
  1853.         for (row = 0; ScreenLines[row]; row++)
  1854.             new_free(&ScreenLines[row]);
  1855.         if (!window && LogLine)
  1856.             LogLine = LogLine->next;
  1857.         if (!LogLine)
  1858.             return NULL;
  1859.         TheirLines = split_up_line(LogLine->msg);
  1860.         for (row = 0; TheirLines[row]; row++)
  1861.         {
  1862.             ScreenLines[row] = TheirLines[row];
  1863.             TheirLines[row] = NULL;
  1864.         }
  1865.         if (window)
  1866.             return NULL;
  1867.     }
  1868.     return ScreenLines[--row];
  1869. }
  1870.  
  1871. static    void
  1872. display_lastlog_lines(start, end, window)
  1873.     long    start,
  1874.         end;
  1875.     Window    *window;
  1876. {
  1877.     Display    *Disp;
  1878.     char    *Line;
  1879.     int    i;
  1880.  
  1881.     (void)next_line_back(window);
  1882.  
  1883.     for (i = window->new_scrolled_lines; i--;)
  1884.         (void)next_line_back(NULL);
  1885.  
  1886.     for (i = 0, Disp = window->top_of_display; i < window->display_size;
  1887.             Disp = Disp->next, i++)
  1888.         if (Disp->linetype)
  1889.             (void)next_line_back(NULL);
  1890.  
  1891.     for (i = 0; i < start; i++)
  1892.         (void)next_line_back(NULL);
  1893.  
  1894.     for (; i < end; i++)
  1895.     {
  1896.         if (!(Line = next_line_back(NULL)))
  1897.             break;
  1898.         term_move_cursor(0, window->top + window->menu.lines +
  1899.             window->scrolled_lines - i - 1);
  1900.         rite(window, Line, 0, 0, 1, 0);
  1901.     }
  1902. }
  1903.  
  1904. extern    void
  1905. scrollback_backwards_lines(ScrollDist)
  1906.     int    ScrollDist;
  1907. {
  1908.     Window    *window;
  1909.  
  1910.     Debug((3, "scrollback_backwards_lines(%d)", ScrollDist));
  1911.     window = curr_scr_win;
  1912.     if (!window->scrolled_lines && !window->scroll)
  1913.     {
  1914.         term_beep();
  1915.         return;
  1916.     }
  1917.     Debug((3, "scrolled_lines = %d", window->scrolled_lines));
  1918.     window->scrolled_lines += ScrollDist;
  1919.  
  1920.     Debug((3, "going to term_scroll(%d, %d, %d)",window->top + window->menu.lines,
  1921.             window->top + window->menu.lines + window->display_size - 1, -ScrollDist));
  1922.     term_scroll(window->top + window->menu.lines, window->top + window->menu.lines + window->display_size - 1, -ScrollDist);
  1923.  
  1924.     Debug((3, "scrolled_lines = %ld, new_scrolled_lines = %ld, display_size = %d", window->scrolled_lines,
  1925.             window->new_scrolled_lines, window->display_size));
  1926.  
  1927.     Debug((3, "going to display_lastlog_lines(%ld, %ld, %s)", window->scrolled_lines - ScrollDist,
  1928.             window->scrolled_lines, window->name));
  1929.     display_lastlog_lines(window->scrolled_lines - ScrollDist, window->scrolled_lines, window);
  1930.     cursor_not_in_display();
  1931.     update_input(UPDATE_JUST_CURSOR);
  1932. }
  1933.  
  1934. extern    void
  1935. scrollback_forwards_lines(ScrollDist)
  1936.     int    ScrollDist;
  1937. {
  1938.     Window    *window;
  1939.  
  1940.     Debug((3, "scrollback_forward_lines(%d)", ScrollDist));
  1941.     window = curr_scr_win;
  1942.     if (!window->scrolled_lines)
  1943.     {
  1944.         term_beep();
  1945.         return;
  1946.     }
  1947.     if (ScrollDist > window->scrolled_lines)
  1948.         ScrollDist = window->scrolled_lines;
  1949.  
  1950.     Debug((3, "scrolled_lines = %d", window->scrolled_lines));
  1951.     window->scrolled_lines -= ScrollDist;
  1952.     Debug((3, "going to term_scroll(%d, %d, %d)", window->top + window->menu.lines,
  1953.             window->top + window->menu.lines + window->display_size - 1, ScrollDist));
  1954.     term_scroll(window->top + window->menu.lines, window->top + window->menu.lines + window->display_size - 1, ScrollDist);
  1955.  
  1956.     Debug((3, "scrolled_lines = %d, new_scrolled_lines = %d, display_size = %d", window->scrolled_lines,
  1957.             window->new_scrolled_lines, window->display_size));
  1958.     if (window->scrolled_lines < window->display_size)
  1959.         redraw_window(window, ScrollDist + window->scrolled_lines - window->display_size);
  1960.  
  1961.     Debug((3, "going to display_lastlog_lines(%ld, %ld, %s)", window->scrolled_lines - window->display_size,
  1962.             window->scrolled_lines - window->display_size + ScrollDist, window->name));
  1963.     display_lastlog_lines(window->scrolled_lines - window->display_size,
  1964.             window->scrolled_lines - window->display_size + ScrollDist, window);
  1965.     cursor_not_in_display();
  1966.     update_input(UPDATE_JUST_CURSOR);
  1967.  
  1968.     if (!window->scrolled_lines)
  1969.     {
  1970.         window->new_scrolled_lines = 0;
  1971.         if (window->hold_mode)
  1972.             hold_mode(window, ON, 1);
  1973.         else
  1974.             hold_mode(window, OFF, 0);
  1975.     }
  1976. }
  1977.  
  1978. extern    void
  1979. scrollback_forwards()
  1980. {
  1981.     scrollback_forwards_lines(curr_scr_win->display_size/2);
  1982. }
  1983.  
  1984. extern    void
  1985. scrollback_backwards()
  1986. {
  1987.     scrollback_backwards_lines(curr_scr_win->display_size/2);
  1988. }
  1989.  
  1990.  
  1991. extern    void
  1992. scrollback_end()
  1993. {
  1994.     Window    *window;
  1995.  
  1996.     window = curr_scr_win;
  1997.     window->new_scrolled_lines = 0;
  1998.  
  1999.     if (!window->scrolled_lines)
  2000.     {
  2001.         term_beep();
  2002.         return;
  2003.     }
  2004.     if (window->scrolled_lines < window->display_size)
  2005.         scrollback_forwards_lines(window->scrolled_lines);
  2006.     else
  2007.     {
  2008.         window->scrolled_lines = 0;
  2009.         redraw_window(window, 1);
  2010.         cursor_not_in_display();
  2011.         update_input(UPDATE_JUST_CURSOR);
  2012.         if (window->hold_mode)
  2013.             hold_mode(window, ON, 1);
  2014.         else
  2015.             hold_mode(window, OFF, 0);
  2016.     }
  2017. }
  2018.  
  2019. /*
  2020.  * scrollback_start: moves the current screen back to the start of
  2021.  * the scrollback buffer..  there are probably cases this doesn't
  2022.  * quite work.. -phone, april 1993.
  2023.  */
  2024. extern    void
  2025. scrollback_start()
  2026. {
  2027.     Window    *window;
  2028.  
  2029.     window = curr_scr_win;
  2030.     if (!window->lastlog_size)
  2031.     {
  2032.         term_beep();
  2033.         return;
  2034.     }
  2035.  
  2036.     if (window->lastlog_size < window->display_size)
  2037.         scrollback_backwards_lines(window->lastlog_size);
  2038.     else
  2039.     {
  2040.         window->scrolled_lines = window->lastlog_size;
  2041.         display_lastlog_lines(window->scrolled_lines -
  2042.             window->display_size, window->scrolled_lines, window);
  2043.         cursor_not_in_display();
  2044.         update_input(UPDATE_JUST_CURSOR);
  2045.         window->new_scrolled_lines = 0;
  2046.         if (window->hold_mode)
  2047.             hold_mode(window, ON, 1);
  2048.         else
  2049.             hold_mode(window, OFF, 0);
  2050.     }
  2051. }
  2052.